package edu.gatech.cs2340.OregonTrail;

import java.util.Iterator;
import java.util.Map;
import java.util.Random;

import javax.swing.JOptionPane;

import edu.gatech.cs2340.OregonTrail.EventSystem.ActorEvent;
import edu.gatech.cs2340.OregonTrail.EventSystem.ActorListener;
import edu.gatech.cs2340.OregonTrail.EventSystem.CommCoordinator;
import edu.gatech.cs2340.OregonTrail.EventSystem.FoodEvent;
import edu.gatech.cs2340.OregonTrail.EventSystem.LoseEvent;
import edu.gatech.cs2340.OregonTrail.EventSystem.OxEvent;
import edu.gatech.cs2340.OregonTrail.EventSystem.WagonEvent;

public class PlayerInventory extends Inventory implements ActorListener {
	private int currentWeight;
	private final int MAX_WEIGHT = 3500;
	private GameDB gameDB;
	private CommCoordinator comm;
	
	public PlayerInventory(Map<Item, Integer> itemList, CommCoordinator comm){
		this.itemAmounts = itemList; 
		currentWeight = 0;
		Iterator<Item> it = itemAmounts.keySet().iterator();
		Item nextItem = null;
		while(it.hasNext()){
			nextItem = it.next();
			currentWeight += nextItem.getWeight() * itemAmounts.get(nextItem);
		}
		
		gameDB = GameDB.getGameDB();
		this.comm = comm;
		this.comm.AddActorListener(this);
	}
	
	public void addItem(Item item) {
		if(currentWeight + item.getWeight() <= MAX_WEIGHT)
			if(itemAmounts.containsKey(item)){
				itemAmounts.put(item, itemAmounts.get(item) + 1);
			}
			else{
				itemAmounts.put(item, 1);
			}
			currentWeight = currentWeight + item.getWeight();
	}

	@Override
	public void addItem(Item item, int amount) {
		if(currentWeight + (item.getWeight() * amount) <= MAX_WEIGHT)
			if(itemAmounts.containsKey(item)){
				itemAmounts.put(item, itemAmounts.get(item) + amount);
			}
			else{
				itemAmounts.put(item, amount);
			}
			currentWeight = currentWeight + (item.getWeight() * amount);
	}

	
	public boolean removeItem(Item item) {
		if(itemAmounts.containsKey(item)){
			if(itemAmounts.get(item) > 0){
				itemAmounts.put(item, itemAmounts.get(item) - 1);
				currentWeight = currentWeight - item.getWeight();
				return true;
			}
			else{
					return false;
			}
		}
		return false;

	}

	@Override
	public boolean removeItem(Item item, int amount) {
		if(itemAmounts.containsKey(item)){
			if(itemAmounts.get(item) >= amount){
				itemAmounts.put(item, itemAmounts.get(item) - amount);
				currentWeight = currentWeight - (item.getWeight() * amount);
				return true;
			}else{
				itemAmounts.put(item, 0);
				return true;
			}
		}
		return false;
	}

	/**
	 * @return the currentWeight
	 */
	public int getCurrentWeight() {
		return currentWeight;
	}

	/**
	 * @return the MAX_WEIGHT
	 */
	public int getMAX_WEIGHT() {
		return MAX_WEIGHT;
	}

	@Override
	public Map<Item, Integer> getStock() {
		return itemAmounts;
		
	}


	public void actorActionPerformed(ActorEvent e) {
		if(e.getClass() == FoodEvent.class){
			handleFoodEvent(e);
		}
		else if(e.getClass() == OxEvent.class){
			handleOxEvent(e);
		}
		else if(e.getClass() == WagonEvent.class){
			handleWagonEvent(e);
		}
		
	}

	private void handleWagonEvent(ActorEvent e) {
		String newMessage = ((WagonEvent) e).getMessage().replace("REPLACEME", ((WagonEvent) e).getBrokenItem().getItemName().toLowerCase());
		if(itemAmounts.get(((WagonEvent)e).getBrokenItem()) == 0){
			JOptionPane.showMessageDialog(null, newMessage + "However, it would appear that you do not have this item. Looks like your journey ends here");
			comm.ThrowGUIEvent(new LoseEvent());
		}
		else{
			JOptionPane.showMessageDialog(null, newMessage);
			removeItem(((WagonEvent) e).getBrokenItem());
		}
		
	}

	private void handleOxEvent(ActorEvent e) {
		int amount = ((OxEvent) e).getAmount();
		Item i = gameDB.getItemByName("An ox");
		
		if(i != null){
			String newMessage = ((OxEvent) e).getMessage().replace("REPLACEME", Integer.toString(amount));
			if(itemAmounts.get(i) > 1){
				removeItem(i, amount);
				JOptionPane.showMessageDialog(null, newMessage);
			}
			else {				
				removeItem(i, amount);
				JOptionPane.showMessageDialog(null, "All of your oxen are dead and your journey ends here.");
				comm.ThrowGUIEvent(new LoseEvent());
			}
		}
		
	}

	private void handleFoodEvent(ActorEvent e) {
		Random rand = new Random();
		int amount = Math.min(((FoodEvent) e).getMaxAmount(), ((FoodEvent) e).getMinAmount()) +
				rand.nextInt(Math.abs(((FoodEvent) e).getMaxAmount()-((FoodEvent) e).getMinAmount()));
		
		Item i = gameDB.getItemByName("Food");
		
		if(i != null){
			if(amount >= 0){
				addItem(i, amount);
			}
			else{
				removeItem(i, amount);
			}
			
			//Holy inline operations, Batman. It looks like the Obsfucator is up to his old tricks
			//We should split this into multiple lines
			JOptionPane.showMessageDialog(null, ((FoodEvent) e).getMessage().replace("REPLACEME", Integer.toString(Math.abs(amount))));
		}
		else{
			JOptionPane.showMessageDialog(null, "Hey. How are you? Sooo, I hate to tell you, but something broke.\n"
					+ "Don't panic! Keep calm, make sure you know where your towel is and report me to the devs.\n"
					+ "For devs: PlayerInventory attempted to process a FoodEvent but was told the food item does not exist");
		}		
	}

}
